<template>
  <h1>App</h1>
  <p>{{ num }}</p>
  <button @click="handleClick">更新</button>
  <!-- ref数据 在模板页面中使用不用.value -->
  <button @click="num++">更新</button>

  <p ref="p">{{ person.name }}</p>
  <p>{{ person.age }}</p>
  <button @click="setAge">更新</button>

  <p>{{ times }}</p>

  <Child :num="num" @setNum="handleClick" ref="child" />
</template>

<script lang="ts">
import {
  reactive,
  ref,
  computed,
  watch,
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
} from "vue";
import Child from "./Child.vue";

export default {
  name: "App",
  components: {
    Child,
  },
  setup() {
    const child = ref();
    const p = ref();

    // 过去同样生命周期函数只能写一个
    // 现在同样生命周期函数可以写n个
    onMounted(() => {
      console.log("onMounted 111");
      console.log(child.value);
      console.log(p.value);
    });

    onMounted(() => {
      console.log("onMounted 222");
    });

    onMounted(() => {
      console.log("onMounted 333");
    });

    onBeforeUnmount(() => {
      console.log("onBeforeUnmount");
    });
    // setup函数相当于beforeCreate和created生命周期函数
    // this是undefined，组合式API中不能使用this
    console.log("setup 执行了", this);

    /*
      结论：
        一般数据都是用ref定义
        如果是表单项数据，用reactive定义
    */

    /******************** 功能111 *********************/
    // 定义 data
    // ref 定义单个响应式数据
    const num = ref(0);
    // const num = ref<number>(0);
    // reactive 定义多个响应式数据
    // const person = reactive({
    //   name: "静哥",
    //   age: 58,
    // });

    // 定义methods
    const handleClick = () => {
      // console.log(this);
      // ref数据在js中使用，不管读取还是更新数据，都需要.value
      // num.value = num.value + 1;
      num.value++;
    };

    // 定义 computed
    // 只读
    const times = computed(() => {
      return num.value + "次";
    });
    // 可读可写
    // const xxx = computed({
    //   get() {},
    //   set() {},
    // });

    // 定义watch
    // 监视ref数据
    watch(
      num,
      (newVal, oldVal) => {
        console.log(newVal, oldVal);
      },
      {
        immediate: true, // 立即监视
        // deep: true,
      }
    );

    /******************** 功能222 *********************/
    // 通过interface接口来定义对象的类型
    // 类型首字母大写
    interface Person {
      name: string;
      age: number;
    }

    const person = reactive<Person>({
      name: "静哥",
      age: 58,
    });

    const setAge = () => {
      // 只有ref数据需要.value，其他数据直接操作即可
      person.age++;
    };

    // 监视reactive数据
    // 监视整个对象直接写
    // watch(person, (newVal, oldVal) => {
    //   console.log(newVal, oldVal);
    // });
    // 监视对象中某个属性的变化，需要写成函数形式
    watch(
      () => person.age,
      (newVal, oldVal) => {
        console.log(newVal, oldVal);
      }
    );

    // 暴露出去, 添加到当前组件实例上（this）
    return {
      num,
      handleClick,
      person,
      setAge,
      times,
      child,
      p,
    };
  },
};
</script>

<style scoped></style>
